/**    @file absyn.h 
    @ingroup absyn
    @brief header file of the abstruct structures of the source language
*/

/**@defgroup abstract_syntax Abstract Syntax
 * The Module of the abstract syntax.<br>
 * This module defines the structures and their creator functions of the absyn 
 * module.
 * @{
*/

#ifndef __ABSYN_H__
#define __ABSYN_H__

#include "symbol.h"
#include "util.h"

typedef int A_pos;

///@brief structure of variables
typedef struct A_var_ *A_var;
///@brief structure of expression
typedef struct A_exp_ *A_exp;
///@brief structure of declaration
typedef struct A_dec_ *A_dec;
///@brief structure of type
typedef struct A_ty_ *A_ty;
///@brief structure of declaration list
typedef struct A_decList_    *A_decList;

///@brief structure of subscript
typedef struct A_subList_    *A_subList;
///@brief structure of expression list
typedef struct A_expList_     *A_expList;
///@brief structure of field
typedef struct A_field_     *A_field;
///@brief structure of field list
typedef struct A_fieldList_    *A_fieldList;
///@brief structure of function declaration
typedef struct A_fundec_    *A_fundec;
///@brief structure of function declaration list
typedef struct A_fundecList_    *A_fundecList;
///@brief structure of expression field
typedef struct A_expField_    *A_expField;
///@brief structure of expression field list
typedef struct A_expFieldList_    *A_expFieldList;
///@brief structure of embed assembly instruction list
typedef struct A_asmList_    *A_asmList;

///Enumerable of calculation opertator type
typedef enum
{
    A_plusOp, A_minusOp, A_timesOp, A_divideOp,
    A_eqOp, A_neqOp, A_ltOp, A_leOp, A_gtOp,
    A_geOp,
    A_andOp, A_orOp, A_lshiftOp, A_rshiftOp,
    A_arshiftOp, A_xorOp,
    A_selfaddOp    // added by Raymond
} A_oper;

///The declaration of the A_var
/**For every appearance of variable in the source file we will create a A_var_
structure to store its information.*/
struct A_var_
{
    enum
    {
        A_simpleVar,     ///< A simple variable without subscript, or field
        A_fieldVar,     ///< A variable like a.b
        A_subscriptVar     ///< A variable like a[3]
    } kind;    ///<The type of var.
            /**<Every variable in the source file is a compond of the 3 kind
            of var. <br>For example, var "a.b[3].c" contains 3 simple vars "a","b"
            and "c". "b[3] "is a subscript var, and "a.b[3]" as whole is a field 
            var.
            */
    A_pos pos;

    union
    {
        S_symbol simple;    /**< For a simple var we only to save its name,
                            witch means a S_symbol structure here*/
        struct
        {
            A_var main;        ///< Main part of a field var
            A_var sub;        ///< Sub part of a field var
        } field;            ///< Field var's info
                            /**< We need to store both the main and the sub
                            part of a field var. In the case "foo.bar", "foo"
                            is the main and the "bar" is sub*/
        struct
        {
            S_symbol name;    ///< Name of a subscript
            A_exp sub[MAX_LINK_SIZE];    ///< things
            int size;        ///< the size of the sub literally
        } subscript;        ///< Subscript var's info
                            /**< In var "foo[a+11]", foo is the name and  the string
                            "a+11" is stored in the sub.                            
                            */
    } /// Union where the infomation is stored    
    u;    
};

///The declaration of the A_exp
/**Everything in the abstract syntax can be stored in the A_exp, this means
A_exp is a common container of the elements of the abstract syntax.
*/
struct A_exp_
{
    ///Which type of element is stored in the A_exp
    enum
    {
        A_varExp, A_intExp, A_stringExp, A_callExp,
        A_opExp, A_recordExp, A_assignExp, A_ifExp,
        A_whileExp, A_forExp, A_seqExp, A_decExp,
        A_asmExp,
        A_breakExp    // Added by Raymond
    } kind;
    A_pos pos;
    union
    {
        A_var         var;
        int         intt;
        string         stringg;
        A_dec        dec;
        struct { S_symbol func; A_expList args;} call;
        struct { A_oper oper; A_exp left; A_exp right;} op;

        ///expression like "a=b+1"
        /**In the case "a = b+1", "a" is stored in var and "b+1" is in exp.*/
        struct { A_var var; A_exp exp;} assign;
        
        /**In the case "if (teststh) then dosth else doelse", test = teststh, 
        then=dosth, elsee = doelse.*/
        struct { A_exp test, then, elsee;} iff;
        
        /**In the case "do sth while(sthelse)", test=sth, body=sthelse. The
        elsee part is optional and can be filled with NULL*/
        struct { A_exp test, body;} whilee;
        
        /**In the case "for(i=0; i<5; i++) do foo()", test="i<5", lo="i=0", 
        hi="i++", body="foo()". And lo, hi, body should be optional*/
        struct { A_exp test, lo, hi, body; bool escape;} forr;
        
        /**Embed assembly instructions.*/
        A_asmList asmm;
        
        ///Seq is a sequence of expressions
        A_expList seq;
    } u;    ///< Where the information of a exp is stored
};

///The declaration of A_dec
/**Every appearence of a declaration in the source file will generate a A_dec
structure in abstract syntax tree.
*/
struct A_dec_
{
    ///The type of the declaration
    enum
    {
        A_funDec,    ///< Function declaration
        A_varDec,    ///< Variable declaration
        A_typeDec    ///< New type declaration
    } kind;

    A_pos pos;
    union
    {    
        ///Function declaration info
        struct
        {
            A_pos pos;         /**< Position of the function declaration*/
            S_symbol name;     /**< Name of the function*/
            A_fieldList params;
                            /**< Parameter list of the function*/
            S_symbol result;/**< Return type */
            A_exp body;        /**< Function body*/
        } fun;        

        struct
        {
            S_symbol var;     ///< Name of the var
            S_symbol typ;     ///< Which type is it
            A_exp init;     ///< The initalization expression
            bool escape;    ///< If it is a escape variable
        } var;        ///<Variable declaration info

        ///New type declaration info
        A_ty ty;
    } u;
};

///declaration of A_ty structure
/**A type definition in the source file will be represented by the A_ty
structure.
*/
struct A_ty_
{
    ///The type of the A_ty
    enum
    {
        A_nameTy,     ///< Name type means give a type a alias
        A_recordTy, ///< Declare a new record type
        A_arrayTy    ///< Declare a array type
    } kind;
    
    A_pos pos;
    union
    {
        struct
        {
            S_symbol name;
            S_symbol ty;
        } name;

        struct
        {
            S_symbol name;
            A_fieldList record;
        } record;

        struct
        {
            S_symbol name;
            S_symbol type;
            int dim;
            A_subList size;
        } array;
    } u;
};

struct A_subList_ { A_exp data; A_subList next; };
struct A_field_ { S_symbol name, typ; A_pos pos; bool escape;};
struct A_fieldList_ { A_field data; A_fieldList next; };
struct A_expList_ { A_exp data; A_expList next;};
struct A_expField_ { S_symbol name; A_exp exp;};
struct A_expFieldList_ { A_expField data; A_expFieldList next;};
struct A_asmList_ { string code; A_asmList next;};

// Function Prototypes
// Creator of the structures
A_var A_SimpleVar(A_pos pos, S_symbol sym);
A_var A_FieldVar(A_pos pos, A_var main, A_var sub);
A_var A_SubscriptVar(A_pos pos, S_symbol name, A_subList size);

A_exp A_VarExp(A_pos pos, A_var var);
A_exp A_IntExp(A_pos, int i);
A_exp A_StringExp(A_pos pos, string s);
A_exp A_CallExp(A_pos pos, S_symbol func, A_expList args);
A_exp A_OpExp(A_pos pos, A_oper oper, A_exp left, A_exp right);

A_exp A_SeqExp(A_pos pos, A_expList seq);
A_exp A_AssignExp(A_pos pos, A_var var, A_exp exp);
A_exp A_IfExp(A_pos pos, A_exp test, A_exp then, A_exp elsee);
A_exp A_WhileExp(A_pos pos, A_exp test, A_exp body);
A_exp A_ForExp(A_pos pos, A_exp lo, A_exp test, A_exp hi,
            A_exp body, bool escape);
A_exp A_DecExp(A_pos pos, A_dec);
A_exp A_AsmExp(A_pos pos, A_asmList asmm);

A_exp A_BreakExp();

A_dec A_FunDec(A_pos pos, S_symbol name, A_fieldList params,
        S_symbol result, A_exp body);
A_dec A_VarDec(A_pos pos, S_symbol var, S_symbol typ, A_exp init);
A_dec A_TypeDec(A_pos pos, A_ty ty);

A_ty A_NameTy(A_pos pos, S_symbol name, S_symbol ty);
A_ty A_RecordTy(A_pos pos, S_symbol name, A_fieldList record);
A_ty A_ArrayTy(A_pos pos, S_symbol name, S_symbol array, A_subList sub);

A_field A_Field( A_pos pos, S_symbol name, S_symbol typ, bool escape);
A_fieldList A_FieldList( A_field data, A_fieldList next);
A_expList A_ExpList(A_exp data, A_expList next);

A_expField A_ExpField(S_symbol name, A_exp exp);
A_expFieldList A_ExpFieldList(A_expField data, A_expFieldList next);
A_asmList A_AsmList(string code, A_asmList next);
A_subList A_SubList(A_exp data, A_subList next);

/**
    @}
*/
#endif
